package com.pi.shisan.util.spipoint;

import com.pi.shisan.common.NumberUtil;
import com.pi.shisan.util.DefaultFont8x8;

/**
 * 将坐标点转换为多段LED矩阵的点
 */
public class MergedSpi implements MultipleXyToSpiConverter{
    private int w;
    private int h;
    private SimpleXyToSpiConverter[] allSpi;

    private boolean useRotate;
    //以LED矩阵为单位，比如一个8x8LED矩阵，w = 1, h = 1
    public MergedSpi(int w, int h) {
        this.w = w;
        this.h = h;
        allSpi = new SimpleXyToSpiConverter[w*h];
        for (int i = 0; i < allSpi.length; i++) {
            allSpi[i] = new SpiPoint();
        }
    }
    /**
     * 如，在第二排、第四排、第六排等等以次类推需要旋转并交替位置，传true
     * 在第一排、第三排、第五排等需要旋转并交替位置传0
     */
    public MergedSpi(int w, int h, boolean useRotate) {
        this.w = w;
        this.h = h;
        allSpi = new SimpleXyToSpiConverter[w*h];
        if (useRotate) {
            for (int i = 0; i < allSpi.length; i++) {
                allSpi[i] = (i / w & 1) == 0 ? new SpiPoint() : new SpiToPointRotate180();
            }
        } else {
            for (int i = 0; i < allSpi.length; i++) {
                allSpi[i] = new SpiPoint();
            }
        }
        this.useRotate = useRotate;
    }

    @Override
    public void add(int x, int y) {
        if (x < 0 || y < 0) {
            throw new RuntimeException("x or y can't less than 0.");
        }
        if (x >= (w << 3) || y >= (h << 3)) {
            throw new RuntimeException("x or y can't great than max val.");
        }
        put(x,y);
    }

    @Override
    public void put(int x, int y) {
        if (x < 0 || y < 0 || x >= (w << 3) || y >= (h << 3)) {
            return;
        }
        allSpi[needChangeIndexPlace((y >> 3) * w + (x >> 3))].add(x & 7,y & 7);
    }

    @Override
    public void put(int xy) {
        put(NumberUtil.toX(xy), NumberUtil.toY(xy));
    }

    @Override
    public void remove(int x, int y) {
        if (x < 0 || y < 0) {
            throw new RuntimeException("x or y can't less than 0.");
        }
        if (x >= (w << 3) || y >= (h << 3)) {
            throw new RuntimeException("x or y can't great than max val.");
        }
        delete(x,y);
    }

    @Override
    public void delete(int x, int y) {
        if (x < 0 || y < 0 || x >= (w << 3) || y >= (h << 3)) {
            return;
        }
        allSpi[needChangeIndexPlace((y >> 3) * w + (x >> 3))].remove(x & 7,y & 7);
    }

    @Override
    public void delete(int xy) {
        delete(NumberUtil.toX(xy), NumberUtil.toY(xy));
    }

    @Override
    public long[] toSpiPoints() {
        long[] allPoints = new long[allSpi.length];
        for (int i = 0; i < allSpi.length; i++) {
            allPoints[i] = allSpi[i].toSpiPoint();
        }
        return allPoints;
    }

    @Override
    public int getW() {
        return w;
    }

    @Override
    public int getH() {
        return h;
    }

    @Override
    public void clear() {
        for (SimpleXyToSpiConverter spi : allSpi) {
            spi.clear();
        }
    }

    @Override
    public String toString() {
        String[] all = new String[allSpi.length * 8];
        int index = 0;
        for (int i = 0; i < allSpi.length; i++) {
            String[] one = allSpi[i].toString().split("\n");
            for (String s : one) {
                all[index++] = s;
            }
        }
        StringBuilder allString = new StringBuilder();
        index = 0;
        for (int i = 0; i < allSpi.length;) {
            allString.append(all[index + (needChangeIndexPlace(i++)<<3)]);
            if (i % w == 0) {
                allString.append("\n");
                if ((++index & 7) == 0) {
                    index = 0;
                    continue;
                }
                i-= w;
                continue;
            }
            allString.append(" ");
        }
        return allString.toString();
    }

    private int needChangeIndexPlace(int index) {
        if (useRotate) {
            return (index / w & 1) == 0 ? index : changeIndexPlace(index);
        }
        return index;
    }

    private int changeIndexPlace(int index) {
        int min = index / w * w;
        int max = min + w - 1;
        int middle = min + (max - min) / 2;
        return index <= middle ? max - (index - min) : min + (max - index);
    }

    public static void main(String[] args) {
//        MergedSpi spi = new MergedSpi(4,3,1);
//        spi.add(9,8);
//        System.out.println(spi.toString());
//        -1177146314433392221 阴
//                * -139331681760406890 雨
//                * 1157443059648041008 小
//                * 1157443787613029506 大
//                * 2594241765877284900 晴
//                * 14157527745973248 雾
//                * -7902646545863634432 雪


//        MergedSpi spi2 = new MergedSpi(4,3,true);
//        spi2.add(9,8);
//        spi2.add(1,1);
//        System.out.println(spi2.toString());

        MergedSpi spi2 = new MergedSpi(4,3,false);
        int[] points = DefaultFont8x8.getPointsAsXy(14157527745973248L);
        for (int xy : points) {
            spi2.put(xy);
        }
        System.out.println(spi2.toString());
    }
}
